#!/usr/bin/env python
from google.appengine.ext import db
import webapp2
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp import util
from google.appengine.api import urlfetch
from google.appengine.api import mail
from google.appengine.runtime import DeadlineExceededError
from google.appengine.ext import deferred

try: import simplejson as json
except ImportError: import json

import datetime
import facebook
#import urllib
import math
import logging
import sys

# the ValtoUser model.
class ValtoUser(db.Model):
    fbuserid = db.StringProperty()
    firstname = db.StringProperty()
    lastname = db.StringProperty()
    name = db.StringProperty()
    creationdate = db.DateTimeProperty(auto_now_add=True)
    lastlogindate = db.DateTimeProperty()
    profilePic = db.LinkProperty()
    email = db.EmailProperty()
    fbaccesstoken = db.StringProperty()
    fbaccesstokenexpdate = db.DateTimeProperty()
    
    def __eq__(self, other):
        if isinstance(other, ValtoUser):
            return self.fbuserid == other.fbuserid
        return NotImplemented

# the ValtoEvent model
class ValtoEvent(db.Model):
    name = db.StringProperty()
    description = db.TextProperty()
    owner = db.ReferenceProperty(ValtoUser, collection_name = "eventsOwnedByUser")
    minlocation = db.GeoPtProperty()
    maxlocation = db.GeoPtProperty()
    creationdate = db.DateTimeProperty(auto_now_add=True)
    startdate = db.DateTimeProperty()
    enddate = db.DateTimeProperty()
    eventPicture = db.BlobProperty()
    password = db.StringProperty()
    deleted = db.BooleanProperty()
    
# save users who checked in to each event
class ValtoUsersEvents(db.Model):
    user = db.ReferenceProperty(ValtoUser,collection_name = "eventsCheckedInByUser")    

# the ValtoItem model
class ValtoItem(db.Model):
    user = db.ReferenceProperty(ValtoUser,collection_name = "itemsUplodedByUser")
    comment = db.TextProperty()
    photo = db.LinkProperty()
    thumbnail = db.LinkProperty()
    smallPhoto = db.LinkProperty()
    date = db.DateTimeProperty(auto_now_add=True)
    lastUpdate = db.DateTimeProperty(auto_now_add=True)
    deleted = db.BooleanProperty()
    uploadedToFB = db.BooleanProperty()
    
# global utilities
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) else None

#
def getUserFromFBToken(fb_access_token):
    # find the user with this Facebook access token
    user = db.GqlQuery("SELECT * FROM ValtoUser WHERE fbaccesstoken = :1", fb_access_token).get()
    
    # if such user exists check the expiration date of the token 
    if user is not None: #and user.fbaccesstokenexpdate < datetime.datetime.utcnow():
        return user
    
    # check Facebook access token is valid
    url = "https://graph.facebook.com/me?access_token=" + fb_access_token 
    result = urlfetch.fetch(url)
    if result.status_code != 200:
        return None
    

    # parse the results json and create new Valto user object
    newUser = parseFacebookUserToValtoUser(result.content, fb_access_token)
#    if ((db.GqlQuery("SELECT * FROM ValtoUser WHERE fbuserid = :1", newUser.fbuserid).get()) is None):
#        newUser.put()

    return newUser

#check if there is a valtoUser for this facebook user id
def checkValtoUserFromFBUserID (fbUserId):
    # find the user with this Facebook User ID
    user = db.GqlQuery("SELECT * FROM ValtoUser WHERE fbuserid = :1", fbUserId).get()
    if user is not None: #and user.fbaccesstokenexpdate < datetime.datetime.utcnow():
        return user
    
    return None
    
#
def parseFacebookUserToValtoUser(fbuserjson, fb_access_token):
    # load the JSON data from the string parameter
    data = json.loads(fbuserjson)
    
    user = checkValtoUserFromFBUserID(data["id"])
    
    if user is not None:
        return user
    
#    url = "https://graph.facebook.com/" + data["id"] +  "/picture"
#    picResult = urlfetch.fetch(url)
    
    # parse Facebook user JSON create a new user object
    valtoUser = ValtoUser(
                    fbuserid = data["id"],
                    firstname = data["first_name"], 
                    lastname = data["last_name"],
                    name = data["name"],
                    email = data["email"],
 #                   profilePic = picResult.final_url,
                    creationdate = datetime.datetime.utcnow(),
                    lastlogindate = datetime.datetime.utcnow(),
                    fbaccesstoken = fb_access_token,
                    fbaccesstokenexpdate = datetime.datetime.utcnow() + datetime.timedelta(hours = 5),
                    )
    
    valtoUser.put()   
    return valtoUser

class MainHandler(webapp2.RequestHandler):
    def get(self):
        self.response.out.write(template.render("slideshow.html", {}))
        
class AlbumHandler(webapp2.RequestHandler):
    def get(self):
        self.response.out.write(template.render("album.html", {}))

class EventsHandler(webapp2.RequestHandler):
    # List Events function
    def get(self):
        # validate the user session
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if user is None:
            self.error(403)
            return
        
        # load the JSON data of the request
        locationlat = float(self.request.get('location_lat'))
        locationlon = float(self.request.get('location_lon'))

        # run a query to find all nearby events for the user location
        results = ValtoEvent.all()
        
        # return them in JSON object
        events = []
        for event in results:
            #check if the event is relevant to return it in the list
            if  event.deleted == False and \
                event.startdate <= datetime.datetime.utcnow() and \
                event.enddate >= datetime.datetime.utcnow() and \
                event.maxlocation.lon >= locationlon and \
                event.maxlocation.lat >= locationlat and \
                event.minlocation.lon <= locationlon and \
                event.minlocation.lat <= locationlat:
                # get event location from our data stored in the DB                    

                allUsersInEvent = db.GqlQuery("SELECT * FROM ValtoUsersEvents WHERE ANCESTOR IS :1 ", event.key())
                numOfUsersCheckedIn = allUsersInEvent.count()
                #check if the user checked in to this event or not
                userCheckedIn = db.GqlQuery("SELECT * FROM ValtoUsersEvents WHERE ANCESTOR IS :1 AND user = :2", event.key(), user)
                distance = calcDistanceFromUser(event,locationlat,locationlon)

                #flag if the user checked in or not
                if (userCheckedIn.get() is None): 
                    checkedIn = False
                else:
                    checkedIn = True
                    
                if (user == event.owner):
                    owner = True
                else:
                    owner = False
                    
                events.append( parseEventToJson(event,numOfUsersCheckedIn,owner,checkedIn,distance))
                    

        # send them to the client as JSON
        self.response.out.write(json.dumps({"data" : events}))
     
    # Create new event
    def post(self):
        # validate the user session
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if user is None:
            self.error(403)
            return
        
        result = createOrUpdateEventDetails(json.loads(self.request.body),user,None,"create")

        if (result == 403):
            self.error(403)
        else:
            self.response.out.write(result)
            

class EventItemsHandler(webapp2.RequestHandler):
    # Post Item to Event function
    def post(self, event_id):
        # validate the user session
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if user is None:
            self.error(403)
            return
        
        # load the request body
        data = json.loads(self.request.body)

        # find the event model
        event = ValtoEvent.get_by_id(int(event_id))
        if event is None or event.deleted == True:
            self.error(404)
            return

        # create the item
        item = ValtoItem(
            parent = event,
            user = user,
            comment = data["comment"],
            photo = data["photo"],
            thumbnail = data["thumbnail"],
            smallPhoto = data["smallPhoto"],
            date = datetime.datetime.utcnow(),
            deleted = False,
        #    uploadedToFB = data["uploadedToFB"],
        )
        item.put()
        
        checkInUserToEvent(user,event)

        # send it back, and include the new ID.
        self.response.out.write(json.dumps({
            "id" : item.key().id(),
            "comment" : data["comment"],
            "photo" : data["photo"],
            "smallPhoto" : data["smallPhoto"],
            "thumbnail" : data["thumbnail"],
            "date" : json.dumps(item.date, default=dthandler),
        }))

    # Get Event Feed function
    def get(self,event_id):
        # find the event model
        event = ValtoEvent.get_by_id(int(event_id))
        if event is None or event.deleted == True:
            self.error(404)
            return
        
        # validate the user session only if facebook access token is provided
        user = None
        if "Facebook-Access-Token" in self.request.headers.keys():
            fbtoken = self.request.headers["facebook-access-token"]
            user = getUserFromFBToken(fbtoken)
            if user is None:
                self.error(403)
                return


        # get all requested items        
        requestedItems = self.request.get("order")
        if (requestedItems != u'recent'):
            nofrag_fromdate = self.request.get("from_date").replace('"', '').split('.')[0]
            requestedDate = datetime.datetime.strptime(nofrag_fromdate, '%Y-%m-%dT%H:%M:%S')
        
        if (requestedItems == u'recent'):
            recentItemsQuery = db.GqlQuery("SELECT * FROM ValtoItem WHERE ANCESTOR IS :1 ORDER BY date DESC", event.key())            
        elif (requestedItems == u'after'):
            # run a recentItemsQuery to find all recentItems posted after date
            recentItemsQuery = db.GqlQuery("SELECT * FROM ValtoItem WHERE ANCESTOR IS :1 AND date > :2 ORDER BY date ASC", event.key(), requestedDate)
        elif (requestedItems == u'before'):
            # run a recentItemsQuery to find all recentItems posted before date
            recentItemsQuery = db.GqlQuery("SELECT * FROM ValtoItem WHERE ANCESTOR IS :1 AND date < :2 ORDER BY date DESC", event.key(), requestedDate)
        else:
            # couldn't provide a value for local variable 'recentItemsQuery' (unbound local error), must return then 
            return
        
        resultitems = recentItemsQuery.fetch(int(self.request.get('maximum_items')))
        resultitems.sort(cmp=None, key=lambda VatltoItem: VatltoItem.date, reverse=False)

        fromUser = self.request.get("fromUser")
        if (fromUser == u'friends'):        
            #access user facebook profile and get friends list
            friendsList = getUserFriendsList(user,self.request.headers["facebook-access-token"])
            # get the list of facebook id's of the user friends who are checked in to this event
            checkedInFriendsList = getFriendsCheckedInList(user,event,friendsList)


        # build the results json and write it back as a response
        recentItems = []
        for item in resultitems:
            if (item.deleted is False or not item.deleted):
                #calculate time difference in seconds and return it
                fromUser = self.request.get("fromUser")
                if (fromUser == u'friends'):
                    if ((not item.user.fbuserid in checkedInFriendsList) and (item.user.fbuserid != user.fbuserid)):
                        continue
                elif (fromUser == u'me'):
                    if (item.user.fbuserid != user.fbuserid):
                        continue
                   
                currentTime = datetime.datetime.utcnow()
                delta = currentTime - item.date
                secondsdiff = delta.total_seconds()
                millisecondsdiff = secondsdiff*1000
                # check whether this user has permissions to delete the current item
                if (user is not None and (user == item.user or user == event.owner)):
                    editable = True    
                else:
                    editable = False
                recentItems.append({
                    "id" : item.key().id(),
                    "comment" : item.comment,
                    "photo" : item.photo,
                    "thumbnail" : item.thumbnail,
                    "smallPhoto" : item.smallPhoto,
                    "date" : json.dumps(item.date, default=dthandler),
                    "editable" : editable, 
                    "fbuserid" : item.user.fbuserid,
                    "name" : item.user.name,
                    "millisecondsDiff" : millisecondsdiff
                })

        if (requestedItems != u'recent'):                
            nofrag_fromdate = self.request.get("lastUpdate").replace('"', '').split('.')[0]
            lastUpdateRequested = datetime.datetime.strptime(nofrag_fromdate, '%Y-%m-%dT%H:%M:%S')
        
            # run query to get last updated items that was deleted
            deletedItemsQuery = db.GqlQuery("SELECT * FROM ValtoItem WHERE ANCESTOR IS :1 AND lastUpdate > :2 AND deleted = TRUE ORDER BY lastUpdate ASC", event.key(), lastUpdateRequested)
        
            deletedItems = []
            for item in deletedItemsQuery:
                deletedItems.append(
                    item.key().id()
                )
                
        else:
            deletedItems = []     

        currentTime = datetime.datetime.utcnow()
            
        eventDetails = { "id" : event.key().id(),
                         "name" : event.name,
                         "description" : event.description,
                         "start_date" : json.dumps(event.startdate, default=dthandler),
                         "end_date" : json.dumps(event.enddate, default=dthandler),
                          }            

        # send them to the client as JSON
        self.response.out.write(json.dumps({"recentItems" : recentItems,                                          
                                            "deletedItems" : deletedItems,
                                            "lastUpdate" : json.dumps(currentTime, default=dthandler),
                                            "eventDetails" : eventDetails
                                            }))
        

    # update events details 
    def put(self,event_id):
        # validate the user session
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if user is None:
            self.error(403)
            return
        
        result = createOrUpdateEventDetails(json.loads(self.request.body),user,event_id,"update")
        if (result == 403):
            self.error(403)
        else:
            self.response.out.write(result)
            
    # update events details 
    def delete(self,event_id):
        # validate the user session
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if user is None:
            self.error(403)
            return
        
        event = ValtoEvent.get_by_id(int(event_id))
        if event is None or event.deleted == True:
            self.error(404)
            return

        if ((user is None) or (not user == event.owner)):
            self.error(403)
            return
              
        event.deleted = True
        event.put()

def createOrUpdateEventDetails (data,user,event_id,action):

        locationlon = float(data["location_lon"])
        locationlat = float(data["location_lat"])
        radius = float(data["radius"])
        DDdelta = 0.009
        
        if (data["start_date"] > data["end_date"]):
            #self.error(403)
            return 403
        
        # remove microseconds from date since they are not sup8ported in Python 2.5 (which Google Apps Engine runs on)
        nofrag_startdate = data["start_date"].replace('"', '').split('.')[0]
        nofrag_enddate = data["end_date"].replace('"', '').split('.')[0]
        
        if (action == "create"):
        
            event = ValtoEvent(        
                name = data["name"],
                description = data["description"],
                owner = user,
                minlocation = db.GeoPt(locationlat - DDdelta, locationlon - DDdelta), 
                maxlocation = db.GeoPt(locationlat + DDdelta, locationlon + DDdelta),
                creationdate = datetime.datetime.utcnow(),
                startdate = datetime.datetime.strptime(nofrag_startdate, "%Y-%m-%dT%H:%M:%S"),
                enddate = datetime.datetime.strptime(nofrag_enddate, "%Y-%m-%dT%H:%M:%S"),
                password = data["password"],
                deleted = False,
                )
            
            event.put()
            
            if (user.email): 
                sendEmailToUser(event, user, "slideshow")
               
        else: 
            event = ValtoEvent.get_by_id(int(event_id))
            if event is None or event.deleted == True:
#                self.error(404)
                return 403
            
            event.name = data["name"]
            event.description = data["description"]
            event.minlocation = db.GeoPt(locationlat - DDdelta, locationlon - DDdelta) 
            event.maxlocation = db.GeoPt(locationlat + DDdelta, locationlon + DDdelta)
            event.creationdate = datetime.datetime.utcnow()
            event.startdate = datetime.datetime.strptime(nofrag_startdate, "%Y-%m-%dT%H:%M:%S")
            event.enddate = datetime.datetime.strptime(nofrag_enddate, "%Y-%m-%dT%H:%M:%S")
            event.password = data["password"]
            event.deleted = False
            event.put()
 
        #check in user 
        checkInUserToEvent(user,event)
        
        allUsersInEvent = db.GqlQuery("SELECT * FROM ValtoUsersEvents WHERE ANCESTOR IS :1 ", event.key())
        numOfUsersCheckedIn = allUsersInEvent.count()
        msg = json.dumps(parseEventToJson(event,numOfUsersCheckedIn,True,True,0))
          
        return msg

# send email to user for the event according to the link preference, either slideshow or album
def sendEmailToUser (valtoEvent,user,linkPref):
            message = mail.EmailMessage(sender="Valto Application <valtoapplication@gmail.com>",
                            subject="Link to " + valtoEvent.name + " event " + linkPref)
    
            valto_url = "http://valtoapp.appspot.com/" + linkPref + "?id=" + str(valtoEvent.key().id())
            message.to = user.email 
            message.body = """
Thank you for using Valto!
Let the new experience begin!
The link for our %(linkPref)s is %(url)s  
""" % { "linkPref":linkPref ,"url":valto_url}
    
            message.send()
        
# Create new valtoEvent
class CreateNewEventHandler(webapp2.RequestHandler):
    def post(self):
        # validate the user session
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if user is None:
            self.error(403)
            return
        
        result = createOrUpdateEventDetails(json.loads(self.request.body),user,None,"create")
        if (result == 403):
            self.error(403)
        else:            

            self.response.out.write(result)
 
 
class UserProfileHandler(webapp2.RequestHandler):
    # User Profile details
    def get(self):
        # validate the user session
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if user is None:
            self.error(403)
            return
        
        # run a query to find all events created by current user
        eventsByUser = user.eventsOwnedByUser
        numOfOwnedEvents = eventsByUser.count()
        eventsByUserList = eventsByUser.fetch(None)
        eventsByUserListKeys = eventsByUser.fetch(None, keys_only=True)
        itemsByUser = user.itemsUplodedByUser
        numOfItemsUploaded = itemsByUser.count()
        eventsCheckedInByUserRes = user.eventsCheckedInByUser
        eventsCheckedInByUserList = eventsCheckedInByUserRes.fetch(None)
        numOfCheckedInEvents = eventsCheckedInByUserRes.count()

        #merge the lists together
        for checkedInEvent in eventsCheckedInByUserList:
            if (checkedInEvent.parent() is not None) :
                if checkedInEvent.parent().key() in eventsByUserListKeys:
                    numOfCheckedInEvents = numOfCheckedInEvents-1
                    continue
                else:
                    eventsByUserList.append(checkedInEvent.parent())
        
        eventsByUserList.sort(cmp=None, key=lambda ValtoEvent: ValtoEvent.startdate, reverse=False)
        
        # return them in JSON object
        events = []
        for event in eventsByUserList:
            if (event.deleted != True):
                if (user == event.owner):
                    owner = True
                else:
                    owner = False
                    
                allUsersInEvent = db.GqlQuery("SELECT * FROM ValtoUsersEvents WHERE ANCESTOR IS :1 ", event.key())
                numOfUsersCheckedIn = allUsersInEvent.count()
                events.append(parseEventToJson(event,numOfUsersCheckedIn,owner,True,0))
            
        # send them to the client as JSON
        self.response.out.write(json.dumps({
              "name" :user.name,
              "creationDate" : json.dumps(user.creationdate, default=dthandler),
#              "profilePicture" : user.profilePic,
              "numOfOwnedEvents" : numOfOwnedEvents,
              "numOfItemsUploaded" : numOfItemsUploaded,
              "numOfCheckedInEvents" : numOfCheckedInEvents,
              "eventsList" : events}))


def parseEventToJson(event,numOfCheckedIn,owner,userCheckedIn,distance):
    location_lon = (event.minlocation.lon + event.maxlocation.lon) / 2.0  
    location_lat = (event.minlocation.lat + event.maxlocation.lat) / 2.0 
    return {"id" : event.key().id(),
            "name" : event.name,
            "description" : event.description,
            "location_lon" : location_lon,
            "location_lat" : location_lat,
            "start_date" : json.dumps(event.startdate, default=dthandler),
            "end_date" : json.dumps(event.enddate, default=dthandler),
            "numOfUsersCheckedIn" : numOfCheckedIn,
            "owner" : owner,
            "userCheckedIn" : userCheckedIn,
            "distance": distance,
            "password" : event.password,
            }       
    

# Items handler to delete items
class ItemHandler(webapp2.RequestHandler):
    # Delete item from event
    def delete(self,event_id,item_id):
        # find the event model
        event = ValtoEvent.get_by_id(int(event_id))
        if event is None or event.deleted == True:
            self.error(404)
            return

        item = ValtoItem.get_by_id(int(item_id),parent=event)
        if item is None:
            self.error(404)
            return

        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if ((user is None) or (not user == item.user and not user == event.owner)):
            self.error(403)
            return
        
        item.deleted = True
        item.lastUpdate = datetime.datetime.utcnow()
        item.put()
        return
    
# checkIn the user to requested event
class CheckInHandler(webapp2.RequestHandler):
    
    # Check In user to event
    def post(self,event_id):
        
        event = ValtoEvent.get_by_id(int(event_id))
        if event is None or event.deleted == True:
            self.error(404)
            return 
        
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if (user is None):
            self.error(403)
            return
        
        checkInUserToEvent(user,event)
 
        
        
# share the event on facebook
class shareHandler(webapp2.RequestHandler):
    
    # share the event on facebook
    def post(self,event_id):
        
        event = ValtoEvent.get_by_id(int(event_id))
        if event is None or event.deleted == True:
            self.error(404)
            return 
        
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if (user is None):
            self.error(403)
            return
        
        shareEventOnFacebook(self.request.headers["facebook-access-token"],event)

def checkInUserToEvent(user,event):
    
        #check if the user already checked in to this event
        userCheckedIn = db.GqlQuery("SELECT * FROM ValtoUsersEvents WHERE ANCESTOR IS :1 AND user = :2", event.key(), user)      
        if (userCheckedIn.get() is None):        
            valtoUserEvent = ValtoUsersEvents(parent = event,
                                              user = user,
                                              )        
            valtoUserEvent.put()
            sendEmailToUser(event, user, "album")
            
def uploadToFacebook (graph, item, user,albumName,albumID):
    if (albumID is None):
        albumsData = (graph.get_connections("me","albums"))['data']
        for album in albumsData:
            if (album['name'] == albumName):
                albumID = album['id'] 
                break
            
    if (albumID is None):
        new_album = graph.put_object("me","albums", name = albumName)
        albumID = new_album['id']
        
    newPhoto = graph.put_object(albumID,"photos", message = item.comment + "\n" + "Uploaded by Valto application" , url= item.photo)   
    photoID = newPhoto['id']

   #msg = item.comment + "\n" + "Uploaded by Valto application"    
     
     #batch request   
    #return {"method": "post",
    #        "relative_url": "albumID/photos", 
    #        "body": "message =" + msg  + "&url="  + item.photo,}
            #"body": "message = " + msg + "&url= " + item.photo
                
 
#    try:     

#    except DeadlineExceededError:
#        return

#    headers = {'Content-Length': "0"}
#    conn = httplib.HTTPConnection("https://graph.facebook.com")
#    conn.request("POST", "/" + photoID + "/tags/" + item.user.fbuserid, None, headers)
#    resp = conn.getresponse()

# upload all photos from event to owner facebook
class exportPhotosHandler(webapp2.RequestHandler):
     
    def post(self,event_id):
        
        event = ValtoEvent.get_by_id(int(event_id))
        if event is None or event.deleted == True:
            self.error(404)
            return 
        
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if (user is None):
            self.error(403)
            return
        
        facebookAccessToken = self.request.headers["facebook-access-token"]
        exportPhotosFunc(event,user,facebookAccessToken,None,None,None,None)
        
def exportPhotosFunc(event,user,facebookAccessToken,start_key,albumID,photoNum,albumNum):        
        eventPhotos = ValtoItem.all().ancestor(event)
        if start_key:
            eventPhotos.filter("__key__ >", start_key)             
        count = eventPhotos.count()
        if albumNum is None:
            if count>200:
                albumNum = 1
            else:
                albumNum = ""
                
        if photoNum is None:
            photoNum = 1
        
        albumName = event.name + " " + albumNum

        if albumID is None: 
            albumID = createNewAlbumInFacebook(facebookAccessToken, albumName)
            
        eventsPhotosList = eventPhotos.fetch(count)
        eventsPhotosList.sort(cmp=None, key=lambda VatltoItem: VatltoItem.date, reverse=False)
        graph = facebook.GraphAPI(facebookAccessToken)
       # uploadRequest = []
      #  try:
        for photo in eventsPhotosList:
            if (photoNum > 199):
                albumNum = albumNum + 1 
                albumName = event.name + " " + albumNum
                albumID = createNewAlbumInFacebook(facebookAccessToken, albumName)
                photoNum = 1
                
                #uploadRequest.append(uploadToFacebook(facebookAccessToken, photo, user, event.name + " " + albumNum, albumID))    
            uploadToFacebook(graph, photo, user, event.name + " " + albumNum, albumID)
            logging.debug("uploaded photo num " + str(photoNum))
            photoNum = photoNum + 1
            start_key = photo.key()
                
        #except DeadlineExceededError:
         #   logging.debug("timed out while uploading photos, defer function")
         #   deferred.defer(exportPhotosFunc, event,user,facebookAccessToken,start_key,albumID,photoNum,albumNum)
         #   return
      #batch request  
        #jsonArray = json.dumps({"batch": uploadRequest})
      #  jsonArray = urllib.urlencode(jsonArray)
        #jsonArray = json.dumps(uploadRequest)
       # graph.request("", post_args = jsonArray)
        #file = urllib.urlopen("https://graph.facebook.com/?" + facebookAccessToken, jsonArray)
        #i = 0       
            
def createNewAlbumInFacebook(facebookAccessToken, albumName):
        graph = facebook.GraphAPI(facebookAccessToken)
        new_album = graph.put_object("me","albums", name = albumName)
        albumID = new_album['id']
        return albumID
    
def shareEventOnFacebook(facebookAccessToken, event):
        graph = facebook.GraphAPI(facebookAccessToken)
        desc = "is at " + event.name + " \n Using Valto android application!"
        attach = {"name": "Valto Application", 
                  "link": "https://www.facebook.com/valtoapp",
                  "caption": "Come, Share and Enjoy!",
                  "description": "Valto is a photo sharing application",
                  "picture": "http://i.imgur.com/qB4of.png"}
                 
        ret = graph.put_wall_post(desc,attachment=attach, profile_id="me")
    
    
# this function calculate the distance between the user location to the event location    
def calcDistanceFromUser (event, lat1,lon1):
    # the algorithm is from: http://www.movable-type.co.uk/scripts/latlong.html
    lon2 = (event.minlocation.lon + event.maxlocation.lon) / 2.0  
    lat2 = (event.minlocation.lat + event.maxlocation.lat) / 2.0
    R = 6371; # radius of earth in km
    dLat = math.radians(lat2-lat1)
    dLon = math.radians(lon2-lon1)
    lat1 = math.radians(lat1)
    lat2 = math.radians(lat2)

    a = math.sin(dLat/2) * math.sin(dLat/2) +  math.sin(dLon/2) * math.sin(dLon/2) * math.cos(lat1) * math.cos(lat2)
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)); 
    d = R * c;
    
    return d

def getUserFriendsList(user,facebookAccessToken):
    
    graph = facebook.GraphAPI(facebookAccessToken)
    friendsData = graph.get_connections("me", "friends")
    friendsList = friendsData['data']
    return friendsList

def getFriendsCheckedInList(user,event,friendsList):
    
    allUsersInEvent = db.GqlQuery("SELECT * FROM ValtoUsersEvents WHERE ANCESTOR IS :1 ", event.key())
    usersCheckedInList = allUsersInEvent.fetch(None)
    friendsCheckedInList = []
    # list of id's of all the users checked in to this event
    usersCheckedInIDList = []
    # list of id's of all friends list
    friendsIDList = []
    for friend in friendsList:
        friendID = friend['id']
        friendsIDList.append(friendID)
    for checkedInUser in usersCheckedInList:
        usersCheckedInIDList.append(checkedInUser.user.fbuserid)
        
    friendsCheckedInList = set(friendsIDList).intersection( set(usersCheckedInIDList) )    
    #friendInEvent = isFbuseridInList(friendID,usersCheckedInList)
    #    if (friendInEvent is not None):
    #        friendsCheckedInList.append(friendInEvent.name)
        
    return friendsCheckedInList
            
def isFbuseridInList(id,list):
    for userEvent in list:
        if userEvent.user.fbuserid == id:
            return userEvent.user
    return None

class  friendsCheckedInHandler(webapp2.RequestHandler):
     
    def get(self,event_id):
        
        event = ValtoEvent.get_by_id(int(event_id))
        if event is None or event.deleted == True:
            self.error(404)
            return 
        
        user = getUserFromFBToken(self.request.headers["facebook-access-token"])
        if (user is None):
            self.error(403)
            return
        
        #access user facebook profile and get friends list
        friendsList = getUserFriendsList(user,self.request.headers["facebook-access-token"])
        # get the list of facebook id's of the user friends who are checked in to this event
        checkedInFriendsList = getFriendsCheckedInList(user,event,friendsList)
        checkedInFriendsNamesList = []
        # for each friend, transfer the facebook id to friend full name from our DB
        for friendID in checkedInFriendsList:
            q = db.Query(ValtoUser)
            friendUser =q.filter("fbuserid", friendID).get()
            checkedInFriendsNamesList.append(friendUser.name)
        
        self.response.out.write(json.dumps({"friendsCheckedInList": checkedInFriendsNamesList}))
    
def main():
    application = webapp2.WSGIApplication([
		('/slideshow', MainHandler),
        ('/album', AlbumHandler),
		
        # REST API
        ('/events', EventsHandler),
        ('/event/(\d+)', EventItemsHandler),
        ('/event/(\d+)/exportPhotos', exportPhotosHandler),
        ('/event/(\d+)/friendsCheckedIn', friendsCheckedInHandler),
        ('/event/(\d+)/item/(\d+)', ItemHandler),
        ('/event/(\d+)/checkin', CheckInHandler),
        ('/event/(\d+)/share', shareHandler),
        ('/userProfile', UserProfileHandler),
        
    ], debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()
